package com.bdqn.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;

/**
 * HelloController
 *
 * @author LILIBO
 * @since 2022-10-18
 */
@Controller
@RequestMapping("/hello") // 整个控制器通用的路径前缀
public class HelloController {

    /**
     * 基本页面访问，浏览器访问一个路径跳转到Controller的某个方法执行
     *
     * @RequestMapping 注解配置该方法为映射器方法（可以处理GET、POST、PUT、DELETE等请求类型）
     * 访问 /hello/hello 路径时调用 hello() 方法
     */
    @RequestMapping("/hello")
    public String hello() {
        System.out.println("------------------- /hello/hello -------------------");
        // 返回需要跳转的视图名称
        return "hello"; // 通过前后缀拼接后找到跳转的页面（prefix + "hello" + suffix）
    }

    /**
     * 使用GET方式访问
     *
     * GET方式访问 /hello/hi1 路径时调用 hi1() 方法
     */
    @GetMapping("/hi1") // 等效于 @RequestMapping(value = "/hi1", method = RequestMethod.GET)
    public String hi1() {
        System.out.println("------------------- /hello/hi1 -------------------");
        // 返回需要跳转的视图名称
        return "hello";
    }

    /**
     * 使用POST方式访问（可以写个HTML页面form表单使用POST方式提交，也可以使用Postman接口测试工具发起请求）
     *
     * POST方式访问 /hello/hi2 路径时调用 hi2() 方法
     */
    @PostMapping("/hi2")
    public String hi2() {
        System.out.println("------------------- /hello/hi2 -------------------");
        // 返回需要跳转的视图名称
        return "hello";
    }

    /**
     * 使用POST方式访问（form表单POST方式提交，传递name、password参数）
     *
     * POST方式访问 /hello/hi3 路径时调用 hi3() 方法
     * 表单数据name属性和方法参数名相同时表单数据自动映射到方法的形参
     */
    @PostMapping("/hi3")
    public String hi3(String name, String password) {
        System.out.println("------------------- /hello/hi3 ------------------- name: " + name + " password: " + password);
        // 返回需要跳转的视图名称
        return "hello";
    }

    /**
     * 使用POST方式访问（form表单POST方式提交，传递n、password参数）
     *
     * POST方式访问 /hello/hi4 路径时调用 hi4() 方法
     * 表单数据name属性和注解@RequestParam中value指定的名称对应，映射到方法的形参。如果页面参数名称和方法形参相同只需写@RequestParam即可
     * @RequestParam(value = "n", required = false, defaultValue = "Boy")
     * - @RequestParam 请求参数
     * - value = "n" 参数名称是n
     * - required = false 非必填参数（默认是必填）
     * - defaultValue = "Boy" 默认值是Boy
     */
    @PostMapping("/hi4")
    public String hi4(@RequestParam(value = "n", required = false, defaultValue = "Boy") String name, @RequestParam String password) {
        System.out.println("------------------- /hello/hi4 ------------------- name: " + name + " password: " + password);
        // 返回需要跳转的视图名称
        return "hello";
    }

    /**
     * 访问 /hello/hi5/{n} 路径时调用 hi5() 方法（在路径上传递参数 REST风格）
     *
     * @PathVariable("n")
     * - @PathVariable 路径参数映射
     * - value = "n" 找到路径上{n}映射到形参
     * - required = false 非必填参数
     */
    @GetMapping("/hi5/{n}")
    public String hi5(@PathVariable("n") String name) {
        System.out.println("------------------- /hello/hi5/{n} ------------------- name: " + name);
        // 需要跳转的视图名称
        return "hello";
    }

    /**
     * 访问 /hello/hi6 路径时调用 hi6() 方法
     *
     * @RequestBody HTTP请求分为请求头和请求体，这里表示请求体Body内容
     * - String body 将请求体内容以字符串的形式映射到参数body
     */
    @PostMapping("/hi6")
    public String hi6(@RequestBody String body) {
        System.out.println("------------------- /hello/hi6 ------------------- body: " + body);
        // 需要跳转的视图名称
        return "hello";
    }

    /**
     * 访问 /hello/hi7 路径时调用 hi7() 方法
     *
     * @RequestParam 接收请求表单中的数据映射到方法形参
     * ModelAndView 模型和视图对象，将需要传递到页面的数据添加到模型中，设置好视图的名称，再返回ModelAndView对象就可以将参数带到相应的页面去，页面通过EL表达式获取作用域中的值
     * 四大作用域（page、request、session、application）设置到ModelAndView中，相当于四大作用域中的的page作用域
     */
    @PostMapping("/hi7")
    public ModelAndView hi7(@RequestParam String name, @RequestParam String password) {
        // 接收请求参数name、password
        System.out.println("------------------- /hello/hi7 ------------------- name: " + name + " password: " + password);

        // 实例化模型和视图对象
        ModelAndView modelAndView = new ModelAndView();

        // 添加Model数据
        modelAndView.addObject("name", name);
        modelAndView.addObject("password", password);

        // 设置View名称
        modelAndView.setViewName("hello");
        return modelAndView;
    }

    /**
     * 访问 /hello/hi8 路径时调用 hi8() 方法
     *
     * Model model 模型对象，作为方法的形参直接可以设置需要传递到页面的参数到模型对象中
     */
    @PostMapping("/hi8")
    public String hi8(Model model, String name, String password) {
        // 接收请求参数name、password
        System.out.println("------------------- /hello/hi8 ------------------- name: " + name + " password: " + password);

        // 添加Model数据
        model.addAttribute("name", name);
        model.addAttribute("password", password);

        // 返回View名称，设置到model中的参数将会带到页面
        return "hello";
    }

    /**
     * 访问 /hello/hi9 路径时调用 hi9() 方法
     *
     * Map<String, Object> map 使用Map作为参数，也相当于Model，四大作用域中的page（page、request、session、application）
     *
     * @return
     */
    @PostMapping("/hi9")
    public String hi9(Map<String, Object> map, String name, String password) {
        System.out.println("------------------- /hello/hi9 ------------------- name: " + name + " password: " + password);
        // 在Map中添加数据相当于添加到Model中
        map.put("name", name);
        map.put("password", password);
        // 返回View名称，可在页面通过EL表达式在page作用域中取值
        return "hello";
    }

    /**
     * 访问 /hello/hi10 路径时调用 hi10() 方法
     *
     * 在方法中可以在需要时将Model、HttpServletRequest、HttpServletResponse、HttpSession等作为参数，从而操作各个对象
     */
    @PostMapping("/hi10")
    public String hi10(Model model, HttpServletRequest request, HttpServletResponse response, HttpSession session, @RequestParam String name) throws UnsupportedEncodingException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        // 手动从请求对象request中获取参数
        String password = request.getParameter("password");

        System.out.println("------------------- /hello/hi10 ------------------- name: " + name + " password: " + password);

        // 将name设置到page作用域
        model.addAttribute("name", "page-" + name);

        // 将name设置到request作用域
        request.setAttribute("name", "request-" + name);

        // 将name设置到session作用域
        session.setAttribute("name", "session-" + name);

        // 返回View名称，可在页面通过EL表达式在各个作用域中取值
        return "hello";
    }

    /**
     * 访问 /hello/hi11 路径时调用 hi11() 方法
     *
     * 在方法中可以在需要时将Model、HttpServletRequest、HttpServletResponse、HttpSession等作为参数，从而操作各个对象
     *
     * 返回 redirect:/hello/hello 表示重定向（让浏览器重新发起一次请求，请求的路径为 /hello/hello 将会映射到 HelloController 类的 hello() 方法）
     */
    @GetMapping("/hi11")
    public String hi11(Model model, HttpServletRequest request, HttpServletResponse response, HttpSession session, String name, String password) throws IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        System.out.println("------------------- /hello/hi11 ------------------- name: " + name + " password: " + password);

        // 将name设置到page作用域
        model.addAttribute("name", "page-" + name);

        // 将name设置到request作用域
        request.setAttribute("name", "request-" + name);

        // 将name设置到session作用域
        session.setAttribute("name", "session-" + name);

        // 重定向，相当于让浏览器重新发起一个请求
        return "redirect:/hello/hello"; // 重定向redirect:/hello/hello
    }

    /**
     * 需要继承AbstractController，通常不使用该方式
     */
    /* @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("Spring MVC框架搭建成功！");
        return null;
    } */

}
